home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / f_timesmooth.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  9.5 KB  |  380 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <crtdbg.h>
  19. #include <windows.h>
  20. #include <commctrl.h>
  21. #include <math.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24.  
  25. #include "filter.h"
  26. #include "cpuaccel.h"
  27. #include "resource.h"
  28. #include "ScriptInterpreter.h"
  29. #include "ScriptValue.h"
  30.  
  31. #define KERNEL        (7)
  32.  
  33. extern HINSTANCE g_hInst;
  34.  
  35. class timesmoothFilterData {
  36. public:
  37.    Pixel32 *accum;
  38.    int framecount;
  39.    int strength;
  40.    int *square_table;
  41.    IFilterPreview *ifp;
  42. };
  43.  
  44. /////////////////////////////////////////////////////////////
  45.  
  46. long timesmooth_param(FilterActivation *fa, const FilterFunctions *ff) {
  47.     fa->dst.offset = fa->src.offset;
  48.     return FILTERPARAM_HAS_LAG(KERNEL/2);
  49. }
  50.  
  51. int timesmooth_start(FilterActivation *fa, const FilterFunctions *ff) {
  52.     timesmoothFilterData *mfd = (timesmoothFilterData *)fa->filter_data;
  53.     int i;
  54.  
  55.     mfd->accum = new Pixel32[fa->src.w * fa->src.h * KERNEL];
  56.     mfd->square_table = new int[255*2+1];
  57.  
  58.     if (!mfd->accum || !mfd->square_table)
  59.         return 1;
  60.  
  61.     memset(mfd->accum, 0, fa->src.w*fa->src.h*KERNEL*4);
  62.  
  63.     mfd->framecount = 0;
  64.  
  65.     for(i=0; i<=511; ++i)
  66.         mfd->square_table[i] = (i-255)*(i-255);
  67.  
  68.     return 0;
  69. }
  70.  
  71. int timesmooth_end(FilterActivation *fa, const FilterFunctions *ff) {
  72.     timesmoothFilterData *mfd = (timesmoothFilterData *)fa->filter_data;
  73.  
  74.     delete[] mfd->accum; mfd->accum = NULL;
  75.     delete[] mfd->square_table; mfd->square_table = NULL;
  76.  
  77.     return 0;
  78. }
  79.  
  80. /////////////////////////////////////////////////////////////
  81.  
  82. #define SCALE(i) (0x0000000100010001i64 * (0x10000 / (i)))
  83. #define SCALE2(i)    SCALE((i)+0),SCALE((i)+1),SCALE((i)+2),SCALE((i)+3),SCALE((i)+4),\
  84.                     SCALE((i)+5),SCALE((i)+6),SCALE((i)+7),SCALE((i)+8),SCALE((i)+9)
  85.  
  86.     static const __int64 scaletab[]={
  87.         0,
  88.         0x00007fff7fff7fffi64,        // special case for 1
  89.         0x00007fff7fff7fffi64,        // special case for 2
  90.         SCALE(3),
  91.         SCALE(4),
  92.         SCALE(5),
  93.         SCALE(6),
  94.         SCALE(7),
  95.         SCALE(8),
  96.         SCALE(9),
  97.         SCALE2(10),
  98.         SCALE2(20),
  99.         SCALE2(30),
  100.         SCALE2(40),
  101.         SCALE2(50),
  102.         SCALE2(60),
  103.         SCALE2(70),
  104.         SCALE2(80),
  105.         SCALE2(90),
  106.         SCALE2(100),
  107.         SCALE2(110),
  108.         SCALE2(120),
  109.     };
  110.  
  111. #undef SCALE
  112.  
  113. static void __declspec(naked) asm_timesmooth_run_MMX(Pixel32 *dstbuf, Pixel32 *accumbuf, int w, int h, int modulo, int kernel, int noffset, int coffset, int strength) {
  114.     static const __int64 sixteen = 0x0010001000100010i64;
  115.     static const __int64 noalpha = 0x0000000000ffffffi64;
  116.     static const __int64 noalpha2 = 0x0000ffffffffffffi64;
  117.  
  118.     __asm {
  119.         push        ebp
  120.         push        edi
  121.         push        esi
  122.         push        ebx
  123.  
  124.         movd        mm6,[esp+36+16]            ;strength+32
  125.         pxor        mm7,mm7
  126.  
  127.         mov            esi,[esp+4+16]            ;src/dstbuf
  128.         mov            edi,[esp+8+16]            ;accumbuf
  129.  
  130.         mov            ebp,[esp+16+16]            ;hcount
  131. yloop:
  132.         mov            ecx,[esp+12+16]            ;wcount
  133. xloop:
  134.         mov            ebx,[esp+28+16]            ;replace offset
  135.         mov            eax,[esp+32+16]            ;center offset
  136.         movd        mm5,[esi]                ;get new pixel
  137.         pand        mm5,noalpha
  138.         movd        [edi+ebx],mm5            ;put into place
  139.         movq        mm4,mm7                    ;clear pixel accumulator
  140.         movd        mm5,[edi+eax]            ;get center pixel
  141.         punpcklbw    mm5,mm7
  142.         add            esi,4
  143.         mov            edx,[esp+24+16]            ;load kernel length
  144.  
  145.         ;mm4: pixel accumulator
  146.         ;mm5: center pixel
  147.         ;mm6: shift
  148.         ;mm7: zero
  149.  
  150. timeloop:
  151.         movd        mm0,[edi]
  152.         movq        mm1,mm5
  153.         pand        mm0,noalpha
  154.         punpcklbw    mm0,mm7
  155.         psubw        mm1,mm0
  156.         pmaddwd        mm1,mm1
  157.         add            edi,4
  158.         punpckldq    mm2,mm1
  159.         paddd        mm1,mm2                    ;mm0 = |r|^2 + |g|^2 + |b|^2 in high dword
  160.         movq        mm2,sixteen
  161.         psrlq        mm1,mm6
  162.         punpcklwd    mm1,mm1
  163.         punpckldq    mm1,mm1
  164.         psubusw        mm2,mm1
  165.         pmullw        mm0,mm2
  166.         psllq        mm2,48
  167.         paddw        mm4,mm2                    ;add scale to scale accumulator
  168.         paddw        mm4,mm0                    ;add scaled pixel to pixel accumulator
  169.         movq        mm0,mm4
  170.         dec            edx
  171.         jne            timeloop
  172.  
  173.         psrlq        mm4,48
  174.         movd        eax,mm4                    ;eax = scale accumulator
  175.  
  176.         pmulhw        mm0,[scaletab+eax*8]    ;produce output pixel
  177.  
  178.         packuswb    mm0,mm0
  179.         dec            ecx
  180.  
  181.         movd        [esi-4],mm0
  182.         jne            xloop
  183.  
  184.         add            esi,[esp+20+16]            ;skip to next scanline
  185.  
  186.         dec            ebp
  187.         jne            yloop
  188.  
  189.         pop            ebx
  190.         pop            esi
  191.         pop            edi
  192.         pop            ebp
  193.         emms
  194.         ret
  195.     };
  196. }
  197.  
  198. static int timesmooth_run(const FilterActivation *fa, const FilterFunctions *ff) {
  199.     timesmoothFilterData *sfd = (timesmoothFilterData *)fa->filter_data;
  200.     int offset1 = sfd->framecount;
  201.     int offset2 = ((sfd->framecount+KERNEL-(KERNEL/2))%KERNEL);
  202.  
  203.     if (MMX_enabled)
  204.         asm_timesmooth_run_MMX(fa->src.data, sfd->accum, fa->src.w, fa->src.h, fa->src.modulo, KERNEL, offset1*4, offset2*4, sfd->strength+32);
  205.     else {
  206.         PixDim w = fa->src.w, x;
  207.         PixDim y = fa->src.h;
  208.         Pixel32 *srcdst = fa->src.data;
  209.         Pixel32 *accum = sfd->accum;
  210.         int *squaretab = sfd->square_table;
  211.         int strength = sfd->strength;
  212.         int i;
  213.  
  214.         do {
  215.             x = w;
  216.             do {
  217.                 const Pixel32 center = accum[offset2];
  218.                 const int *crtab = squaretab + 255 - ((center>>16)&0xff);
  219.                 const int *cgtab = squaretab + 255 - ((center>> 8)&0xff);
  220.                 const int *cbtab = squaretab + 255 - ((center    )&0xff);
  221.                 int raccum = 0, gaccum = 0, baccum = 0;
  222.                 int count = 0;
  223.  
  224.                 accum[offset1] = *srcdst & 0xffffff;
  225.  
  226.                 for(i=0; i<KERNEL; ++i) {
  227.                     const Pixel32 c = *accum++;
  228.                     int cr = (c>>16)&0xff;
  229.                     int cg = (c&0xff00)>>8;
  230.                     int cb = c&0xff;
  231.                     int sqerr = (crtab[cr] + cgtab[cg] + cbtab[cb]) >> strength;
  232.  
  233.                     if (sqerr > 16)
  234.                         sqerr = 16;
  235.  
  236.                     sqerr = 16 - sqerr;
  237.  
  238.                     raccum += cr * sqerr;
  239.                     gaccum += cg * sqerr;
  240.                     baccum += cb * sqerr;
  241.                     count += sqerr;
  242.                 }
  243.  
  244.                 int divisor = ((long *)scaletab)[2*count+1];
  245.  
  246.                 raccum = (raccum * divisor)>>16;
  247.                 gaccum = (gaccum * divisor)>>16;
  248.                 baccum = (baccum * divisor)>>16;
  249.  
  250.                 *srcdst++ = (raccum<<16) + (gaccum<<8) + baccum;
  251.                 
  252.             } while(--x);
  253.  
  254.             srcdst = (Pixel32 *)((char *)srcdst + fa->src.modulo);
  255.  
  256.         } while(--y);
  257.     }
  258.  
  259.     if (++sfd->framecount >= KERNEL)
  260.         sfd->framecount = 0;
  261.  
  262.     return 0;
  263. }
  264.  
  265. static void timesmooth_string(const FilterActivation *fa, const FilterFunctions *ff, char *buf) {
  266.     timesmoothFilterData *mfd = (timesmoothFilterData *)fa->filter_data;
  267.  
  268.     wsprintf(buf, " (%d)", mfd->strength);
  269. }
  270.  
  271. static BOOL APIENTRY timesmoothDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam) {
  272.     timesmoothFilterData *mfd = (timesmoothFilterData *)GetWindowLong(hDlg, DWL_USER);
  273.  
  274.     switch (message)
  275.     {
  276.         case WM_INITDIALOG:
  277.             {
  278.                 HWND hwndItem;
  279.  
  280.                 mfd = (timesmoothFilterData *)lParam;
  281.  
  282.                 SetWindowLong(hDlg, DWL_USER, (LONG)mfd);
  283.  
  284.                 hwndItem = GetDlgItem(hDlg, IDC_STRENGTH);
  285.                 SendMessage(hwndItem, TBM_SETRANGE, TRUE, MAKELONG(0, 10));
  286.                 SendMessage(hwndItem, TBM_SETPOS, TRUE, mfd->strength);
  287.  
  288.                 mfd->ifp->InitButton(GetDlgItem(hDlg, IDC_PREVIEW));
  289.             }
  290.             return (TRUE);
  291.  
  292.         case WM_COMMAND:                      
  293.             switch(LOWORD(wParam)) {
  294.             case IDOK:
  295.                 mfd->ifp->Close();
  296.                 EndDialog(hDlg, 0);
  297.                 return TRUE;
  298.  
  299.             case IDCANCEL:
  300.                 mfd->ifp->Close();
  301.                 EndDialog(hDlg, 1);
  302.                 return TRUE;
  303.  
  304.             case IDC_PREVIEW:
  305.                 mfd->ifp->Toggle(hDlg);
  306.                 return TRUE;
  307.             }
  308.             break;
  309.  
  310.         case WM_HSCROLL:
  311.             mfd->strength = SendDlgItemMessage(hDlg, IDC_STRENGTH, TBM_GETPOS, 0, 0);
  312.             mfd->ifp->RedoFrame();
  313.             break;
  314.  
  315.     }
  316.     return FALSE;
  317. }
  318.  
  319. static int timesmooth_config(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd) {
  320.     timesmoothFilterData *mfd = (timesmoothFilterData *)fa->filter_data;
  321.     timesmoothFilterData mfd2 = *mfd;
  322.     int ret;
  323.  
  324.     mfd->ifp = fa->ifp;
  325.  
  326.     ret = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER_TIMESMOOTH), hWnd, timesmoothDlgProc, (LONG)mfd);
  327.  
  328.     if (ret)
  329.         *mfd = mfd2;
  330.  
  331.     return ret;
  332. }
  333.  
  334. /////////////////////////////////////////////////////////////
  335.  
  336. static void timesmooth_script_config(IScriptInterpreter *isi, void *lpVoid, CScriptValue *argv, int argc) {
  337.     FilterActivation *fa = (FilterActivation *)lpVoid;
  338.  
  339.     timesmoothFilterData *mfd = (timesmoothFilterData *)fa->filter_data;
  340.  
  341.     mfd->strength = argv[0].asInt();
  342. }
  343.  
  344. static ScriptFunctionDef timesmooth_func_defs[]={
  345.     { (ScriptFunctionPtr)timesmooth_script_config, "Config", "0i" },
  346.     { NULL },
  347. };
  348.  
  349. static CScriptObject timesmooth_obj={
  350.     NULL, timesmooth_func_defs
  351. };
  352.  
  353. static bool timesmooth_script_line(FilterActivation *fa, const FilterFunctions *ff, char *buf, int buflen) {
  354.     timesmoothFilterData *mfd = (timesmoothFilterData *)fa->filter_data;
  355.  
  356.     _snprintf(buf, buflen, "Config(%d)", mfd->strength);
  357.  
  358.     return true;
  359. }
  360.  
  361. /////////////////////////////////////////////////////////////
  362.  
  363. struct FilterDefinition filterDef_timesmooth={
  364.     0,0,NULL,
  365.     "temporal smoother",
  366.     "Performs an adaptive smooth along the time axis.\n\n[Assembly optimized][MMX optimized][Lag: 4]",
  367.     NULL,
  368.     NULL,sizeof(timesmoothFilterData),
  369.     NULL,NULL,
  370.     timesmooth_run,
  371.     timesmooth_param,
  372.     timesmooth_config,
  373.     timesmooth_string,
  374.     timesmooth_start,
  375.     timesmooth_end,
  376.  
  377.     ×mooth_obj,
  378.     timesmooth_script_line,
  379. };
  380.